#include <xpam/ui/dc.h>

#pragma comment (lib, "Msimg32.lib")

namespace xpam
{
	namespace ui
	{
		dc::dc()
		{
			_width = 0;
			_height = 0;
			_buffer = 0;
			_dc = 0;
			_bitmap = 0;
		}

		dc::~dc()
		{
			DeleteDC((HDC)_dc);
			DeleteObject((HBITMAP)_bitmap);
		}

		void dc::create(unsigned int width, unsigned int height)
		{
			_width = width;
			_height = height;
			SIZE sz = {_width, _height};
			BITMAPINFO bmi;
			ZeroMemory(&bmi, sizeof(BITMAPINFO));
			bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
			bmi.bmiHeader.biWidth = sz.cx;
			bmi.bmiHeader.biHeight = sz.cy;
			bmi.bmiHeader.biPlanes = 1;
			bmi.bmiHeader.biBitCount = 32;
			bmi.bmiHeader.biCompression = BI_RGB;
			bmi.bmiHeader.biSizeImage = sz.cx * sz.cy * 4;
			_dc = CreateCompatibleDC(NULL);
			_bitmap = CreateDIBSection((HDC)_dc, &bmi, DIB_RGB_COLORS, (void**)&_buffer, NULL, 0x0);
			SelectObject((HDC)_dc, (HBITMAP)_bitmap);
            SelectObject((HDC)_dc, GetStockObject(DC_PEN));
		}

		void dc::from_window(xpam::ui::window & w)
		{
            HWND h = (HWND)w.get_internal_handle();
            _dc = GetDC(h);
            RECT rt;
            GetClientRect(h, &rt);
            _width = rt.right;
            _height = rt.bottom;
		}

        void dc::from_file(const std::string & filename)
        {
            _dc = CreateCompatibleDC(NULL);
            _bitmap = LoadImageA(NULL, filename.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
            BITMAP Bitmap;
            GetObject(_bitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
            _width = Bitmap.bmWidth;
            _height = Bitmap.bmHeight;
            SelectObject((HDC)_dc, _bitmap);
        }

        void dc::draw_line(int x1, int y1, int x2, int y2)
        {
            MoveToEx((HDC)_dc, x1, y1, 0);
            LineTo((HDC)_dc, x2, y2);
        }

        void dc::draw_text(const xpam::rectangle<int> & rect, const std::string & text)
        {
            RECT rt;
            SetRect(&rt, rect.left(), rect.top(), rect.right(), rect.bottom());
            //::SetBkColor((HDC)_dc, );
            ::DrawTextA((HDC)_dc, text.c_str(), text.size(), &rt, DT_CENTER | DT_VCENTER);
        }

        void dc::draw_text(const xpam::rectangle<int> & rect, const std::wstring & text)
        {
            RECT rt;
            SetRect(&rt, 0, 0, rect.right() - rect.left(), rect.bottom() - rect.top());
            //::SetBkColor((HDC)_dc, );
            ::DrawTextW((HDC)_dc, text.c_str(), text.size(), &rt, DT_CENTER | DT_VCENTER | DT_NOCLIP);
        }

        void dc::copy(dc & dc_)
        {
            BitBlt((HDC)_dc, 0, 0, _width, _height, (HDC)dc_._dc, 0, 0, SRCCOPY);
        }

        void dc::fill(unsigned int color)
        {
            int n = width() * height();
            for (int i = 0; i < n; i++)
            {
                _buffer[i] = color;
            }
        }

        void dc::fill(unsigned int color, point<int> pt, size<int> sz)
        {
            int x2 = pt.x + sz.width;
            int y2 = pt.y + sz.height;
            for (int y = pt.y; y < y2; y++)
            {
                for (int x = pt.x; x < x2; x++)
                {
                    (*this)[y][x] = color;
                }
            }
        }

        void dc::copy_alpha(dc & other, const point<int> & pt)
        {
            BLENDFUNCTION blender = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
            ::AlphaBlend((HDC)_dc, pt.x-5, pt.y-5, other.width(), other.height(), (HDC)other._dc, 0, 0, other.width(), other.height(), blender);
        }

        void dc::color(int rgb)
        {
            ::SetDCPenColor((HDC)_dc, rgb);
        }

        void dc::color(int r, int g, int b)
        {
            ::SetDCPenColor((HDC)_dc, RGB(r, g, b));
        }
	}
}